﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ecdl.demo.model.expression;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml.Packaging;

using System.Xml;
using System.Xml.Serialization;
using System.Text.RegularExpressions;

namespace ecdl.demo.model.word {
    public class FontStyleExpression : WordExpression {

        private const string POSITIVE_MESSAGE = "Der gesuchte Absatz wurde richtig formatiert";
        private const string NEGATIVE_MESSAGE = "Der gesuchte Absatz wurde nicht richtig formatiert.";

        private const string PARAGRAPH_NOT_FOUND_MESSAGE = "Der gesuchte Absatz konnte nicht gefunden werden.";

        public String Regex { get; set; }

        public bool BoldExpected { get; set; }
        public bool ItalicExpected { get; set; }
        public bool UnderlineExpected { get; set; }

        protected override ExpressionState Evaluate(WordprocessingDocument document) {
            IEnumerable<Paragraph> allParagraphs = GetAllParagraphs(document);

            foreach (Paragraph p in allParagraphs) {
                string paragraphText = GetText(p);
                if (System.Text.RegularExpressions.Regex.IsMatch(paragraphText, Regex)) {
                    // Paragraph found
                    IEnumerable<Run> runs = p.Descendants<Run>();
                    if (CheckFormating(runs)) {
                        //paragraph found AND formatting is ok
                        return Success(POSITIVE_MESSAGE, NEGATIVE_MESSAGE);
                    }
                    // paragraph found, formatting is MISSING
                    return Fail(NEGATIVE_MESSAGE, POSITIVE_MESSAGE);
                }
            }
            //paragraph not found
            return Fail(PARAGRAPH_NOT_FOUND_MESSAGE);
        }

        private bool CheckFormating(IEnumerable<Run> runs) {
            bool formatOk = true;
            if (BoldExpected && !CheckIfRunsContainAttribute<Bold>(runs)) {
                formatOk = false;
            }
            if (ItalicExpected && !CheckIfRunsContainAttribute<Italic>(runs)) {
                formatOk = false;
            }
            if (UnderlineExpected && !CheckIfRunsContainAttribute<Underline>(runs)) {
                formatOk = false;
            }
            return formatOk;
        }

        private bool CheckIfRunsContainAttribute<T>(IEnumerable<Run> runs)
            where T : OpenXmlElement {

            foreach (Run r in runs) {
                // check if this run contains at least child of type T
                if (r.Descendants<T>().Count() == 0) {
                    return false;
                }
            }
            return true;
        }
    }

    public class FontStyleExpressionDTO : ExpressionDTO {
        public FontStyleExpressionDTO() {

        }

        [XmlAttribute("regex")]
        public string Regex { get; set; }
        [XmlAttribute("bold")]
        public bool Bold { get; set; }
        [XmlAttribute("italic")]
        public bool Italic { get; set; }
        [XmlAttribute("underline")]
        public bool Underline { get; set; }

        public override Expression ToModel(persistence.ModelFactory factory) {
            FontStyleExpression expression = factory.CreateModel<FontStyleExpression>();
            expression.Regex = Regex;
            expression.BoldExpected = Bold;
            expression.ItalicExpected = Italic;
            expression.UnderlineExpected = Underline;
            return expression;
        }
    }
}
